/**
 * 
 */
package com.oron3.bouncer.objects.shapes;




/**
 * @author Ofek
 *
 */
public class Rectangle implements Shape {
	private final LineSegment l1;
	private final LineSegment l2;
	public final Plane p;
	private final LineSegment l3;
	private final LineSegment l4;
	public static final int RELATION_NOT_OVERLAP_INSIDE_BOUNDS_IN_NORAML_DIRECTION = 0;
	public static final int RELATION_NOT_OVERLAP_INSIDE_BOUNDS_IN_OPPOSITE_NORAML_DIRECTION=1;
	public static final int RELATION_NOT_OVERLAP_OUTSIDE_BOUNDS_IN_NORAML_DIRECTION=2;
	public static final int RELATION_NOT_OVERLAP_OUTSIDE_BOUNDS_IN_OPPOSITE_NORAML_DIRECTION=3;
	public static final int RELATION_OVERLAP_INSIDE_BOUNDS = 4;
	public static final int RELATION_OVERLAP_OUTSIDE_BOUNDS = 5;


	/**
	 * NOTE :  
	 * @param p1 
	 * @param p2 
	 * @param p3
	 */
	public Rectangle(final Point p1, final Point p2, final Point p3) {
		p=new Plane(p1,p2,p3);
		l1 = new LineSegment(p1, p2);
		l2 = new LineSegment(p3, p2);
		final Point p2reflection = p1.add(p3.sub(p2));
		l3 = new LineSegment(p1, p2reflection);
		l4 = new LineSegment(p3, p2reflection);
	}
	@Override
	public Shape project(final Shape p) {
		if ( p instanceof Point) {
			final Point project = (Point)this.p.project(p);
			if (l1.project(p)==null || l2.project(p)==null) return null;
			return project;
		} throw new IllegalArgumentException();

	}


	/* (non-Javadoc)
	 * @see com.oron3.bouncer.objects.GLObject#intersects(com.oron3.bouncer.objects.GLObject)
	 */
	@Override
	public boolean intersects(final Shape o) {
		if ( o instanceof Sphere ) {
			final Sphere s = (Sphere) o;
			final Point projection = (Point) project(s.center);
			if (projection==null) return false;
			return new Vector(s.center.sub(projection)).length()<=s.r;
		}
		return false;
	}

	/* (non-Javadoc)
	 * @see com.oron3.bouncer.objects.shapes.Shape#intersection(com.oron3.bouncer.objects.shapes.Shape)
	 */
	@Override
	public Intersection intersection(final Shape o) {
		if ( o instanceof Line ) {

			final Line l = (Line) o;
			if (isInside(l.p1) && isInside(l.p1.add(l.d))) {
				return getIntersectionLineSegment(l);
			}
			final Vector vDirection = l.d;
			final Point p = l.p1;

			final Point project = (Point) project(p);
			if ( project==null ) return null;
			final Vector u = new Vector(project.sub(p));
			final Vector uDirection = u.normalize();
			final float cosa = vDirection.dot(uDirection);

			float vLength;
			if ( cosa==0 ) {
				final Point add = p.add(vDirection.mul(u.length()));
				if ( !isInside(add) ) return null;
				return new Intersection(add);
			}
			if ( cosa<0 ) {
				vLength = u.length()/(-cosa);
				final Point add = p.add(vDirection.mul(-vLength));
				if ( !isInside(add) ) return null;
				return new Intersection(add);
			}
			else {
				vLength = u.length()/(cosa);
				final Point add = p.add(vDirection.mul(vLength));
				if ( !isInside(add) ) return null;
				return new Intersection(add);
			}
		}
		return null;
	}
	/**
	 * @param l 
	 * @return
	 */
	private Intersection getIntersectionLineSegment(final Line l) {
		throw new IllegalArgumentException();
		//		final Intersection intersectionl1 = l1.intersection(l);
		//		final Intersection intersectionl2 = l2.intersection(l);
		//		final Intersection intersectionl3 = l3.intersection(l);
		//		final Intersection intersectionl4 = l4.intersection(l);
		//		return null;
	}
	/* (non-Javadoc)
	 * @see com.oron3.bouncer.objects.shapes.Plane#calcRelation(com.oron3.bouncer.objects.shapes.Shape)
	 */
	@Override
	public int describeRelation(final Shape o) {
		final int planeRelation = p.describeRelation(o);
		if ( o instanceof Point ) {
			if ( planeRelation == Plane.RELATION_IN_BOTH_DIRECTION) 
				throw new IllegalArgumentException();
			final Point p = (Point) o;
			final boolean inside = l1.project(p)!=null && l2.project(p)!=null;
			if ( planeRelation!=Plane.RELATION_OVERLAP ) {
				if ( inside ) {
					if ( planeRelation==Plane.RELATION_IN_NORAML_DIRECTION) return RELATION_NOT_OVERLAP_INSIDE_BOUNDS_IN_NORAML_DIRECTION;
					if ( planeRelation==Plane.RELATION_IN_OPPOSITE_NORAML_DIRECTION) return RELATION_NOT_OVERLAP_INSIDE_BOUNDS_IN_OPPOSITE_NORAML_DIRECTION;
				} else {
					if ( planeRelation==Plane.RELATION_IN_NORAML_DIRECTION) return RELATION_NOT_OVERLAP_OUTSIDE_BOUNDS_IN_NORAML_DIRECTION;
					if ( planeRelation==Plane.RELATION_IN_OPPOSITE_NORAML_DIRECTION) return RELATION_NOT_OVERLAP_OUTSIDE_BOUNDS_IN_OPPOSITE_NORAML_DIRECTION;
				}

			} else {
				if ( inside ) return RELATION_OVERLAP_INSIDE_BOUNDS;
				return RELATION_OVERLAP_OUTSIDE_BOUNDS;
			}
		}
		throw new IllegalArgumentException();
	}
	/* (non-Javadoc)
	 * @see com.oron3.bouncer.objects.shapes.Shape#isInside(com.oron3.bouncer.objects.shapes.Shape)
	 */
	@Override
	public boolean isInside(final Shape o) {
		return describeRelation(o)==RELATION_OVERLAP_INSIDE_BOUNDS;
	}



}
